package com.paradogs.generator.csapi;

import com.baidu.bjf.remoting.protobuf.annotation.ProtobufClass;
import com.gitee.sunchenbin.mybatis.actable.utils.ClassScaner;
import com.paradogs.framework.annotations.serverHandler.PRHandler;
import com.paradogs.framework.annotations.serverHandler.PRMapping;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.core.annotation.AnnotationUtils;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @author: yumi
 * @date: 2025/2/22  20:39
 * @Description: TODO
 */
@Slf4j
public class CsApiGeneratorProcesser {
    public static void main(String[] args) throws IOException {

        List<HandlerInfo> handlerInfos = analysis();

        final String BASE_DIR = "D:\\unity\\paradogs2-sdk\\Assets";

        // 生成对应文件
        FileUtils.forceMkdir(new File(java.lang.String.format("%s\\pd2-sdk\\api", BASE_DIR)));
        tryGen("api3.ftl",
                new File(java.lang.String.format("%s\\pd2-server-sdk\\api_by_auto\\NetMgr.cs", BASE_DIR)),
                Map.of("handlerInfos", handlerInfos, "protobufInfos", analysis2()));

    }

    public static List<HandlerInfo> analysis() {
        Set<Class> handlers = ClassScaner.scan("com.paradogs", PRHandler.class);

        List<HandlerInfo> list = new ArrayList<>();
        for (Class<?> handler : handlers) {
            List<ApiInfo> apiInfos = new ArrayList<>();
            PRMapping clzAnno = AnnotationUtils.getAnnotation(handler, PRMapping.class);
            HandlerInfo handlerInfo = new HandlerInfo();
            handlerInfo.setHandlerName(handler.getSimpleName());
            handlerInfo.setApiInfos(apiInfos);

            for (Method method : handler.getDeclaredMethods()) {
                PRMapping apiAnno = AnnotationUtils.getAnnotation(method, PRMapping.class);
                if (apiAnno == null) continue;

                ApiInfo apiInfo = new ApiInfo();
                apiInfo.setRoute((clzAnno != null ? (clzAnno.value() + ".") : "") + apiAnno.value());
                apiInfo.setRequest(!method.getReturnType().equals(Void.TYPE));

                // 处理返回类型
                Type returnType = method.getGenericReturnType();
                if (method.getReturnType().isAssignableFrom(CompletableFuture.class)) {
                    ParameterizedType futureType = (ParameterizedType) returnType;
                    Type innerType = futureType.getActualTypeArguments()[0];
                    apiInfo.setReturnType(extractInnerTypeName(innerType)); // 递归提取最内层类型
                } else {
                    apiInfo.setReturnType(extractInnerTypeName(returnType));
                }

                apiInfo.setApiName(method.getName());

                // 处理参数（保持不变）
                Parameter[] parameters = method.getParameters();
                if (parameters.length > 0) {
                    Class<?> paramType = parameters[0].getType();
                    apiInfo.setParameterObjectName(paramType.getSimpleName());
                    apiInfo.setParameters(Arrays.stream(paramType.getDeclaredFields())
                            .map(field -> new ParameterInfo(field.getType().getSimpleName(), field.getName()))
                            .collect(Collectors.toList()));
                } else {
                    apiInfo.setParameters(new ArrayList<>());
                }

                apiInfos.add(apiInfo);
            }
            list.add(handlerInfo);
        }
        return list;
    }

    /**
     * 递归提取最内层类型名称
     */
    private static String extractInnerTypeName(Type type) {
        if (type instanceof ParameterizedType) {
            ParameterizedType pType = (ParameterizedType) type;
            Type rawType = pType.getRawType();
            String rawTypeName = ((Class<?>) rawType).getSimpleName();

            // 如果是 Ack 或 CompletableFuture，继续递归解析其泛型参数
            if (rawTypeName.equals("GC") || rawTypeName.equals("CompletableFuture")) {
                Type[] typeArgs = pType.getActualTypeArguments();
                if (typeArgs.length > 0) {
                    return extractInnerTypeName(typeArgs[0]);
                }
            }

            // 其他泛型类型直接返回名称（如 List<String> -> List<String>）
            StringBuilder sb = new StringBuilder(rawTypeName);
            sb.append("<");
            for (int i = 0; i < pType.getActualTypeArguments().length; i++) {
                if (i > 0) sb.append(", ");
                sb.append(extractInnerTypeName(pType.getActualTypeArguments()[i]));
            }
            sb.append(">");
            return sb.toString();
        } else if (type instanceof Class) {
            String simpleName = ((Class<?>) type).getSimpleName();
            if (simpleName.equals("GC")) {
                return "Ack";
            }
            return simpleName;
        }
        return type.getTypeName(); // 其他类型直接返回原始名称
    }

    private static String getSimpleName(Type type) {
        if (type instanceof Class) {
            return ((Class<?>) type).getSimpleName(); // 自定义对象返回简单类名
        } else if (type instanceof ParameterizedType) {
            ParameterizedType pType = (ParameterizedType) type;
            StringBuilder sb = new StringBuilder();
            sb.append(getSimpleName(pType.getRawType())); // 处理原始类型
            Type[] typeArgs = pType.getActualTypeArguments();
            if (typeArgs.length > 0) {
                sb.append("<");
                for (int i = 0; i < typeArgs.length; i++) {
                    if (i > 0) sb.append(", ");
                    sb.append(getSimpleName(typeArgs[i])); // 递归处理泛型参数
                }
                sb.append(">");
            }
            return sb.toString();
        } else if (type instanceof TypeVariable) {
            return ((TypeVariable<?>) type).getName(); // 处理泛型类型变量（如 T）
        } else if (type instanceof WildcardType) {
            return "?"; // 处理通配符类型（如 ?）
        } else if (type instanceof GenericArrayType) {
            GenericArrayType arrayType = (GenericArrayType) type;
            return getSimpleName(arrayType.getGenericComponentType()) + "[]"; // 处理数组类型
        } else {
            return type.getTypeName(); // 其他类型直接返回原始名称
        }
    }

    public static List<ProtoBufInfo> analysis2() {
        Set<Class> protobufEntityClasses = ClassScaner.scan("com.paradogs", ProtobufClass.class);
        return convertClassesToProtoBufInfos(protobufEntityClasses);
    }

    private static void tryGen(String ftl, File output, Map<String, Object> dataModel) {
        try {
            Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
            cfg.setDirectoryForTemplateLoading(new File("paradogs-generator\\src\\main\\resources\\csapi")); // 设置模板加载路径
            cfg.setDefaultEncoding("UTF-8");            // 设置默认编码
            Template template = cfg.getTemplate(ftl);   // 加载模板文件
            Writer out = new FileWriter(output);        // 定义输出文件
            template.process(dataModel, out);           // 合并模板和数据模型
            out.close();                                // 关闭输出流
            System.out.println(">>>> Successfully generated template: " + ftl);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String convertMapFieldToCSharp(Field field) {
        Type type = field.getGenericType();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            Type rawType = parameterizedType.getRawType();
            if (rawType == Map.class) {
                Type[] typeArguments = parameterizedType.getActualTypeArguments();
                if (typeArguments.length == 2) {
                    String keyType = getSimpleName(typeArguments[0]);
                    String valueType = getSimpleName(typeArguments[1]);
                    return "Dictionary<" + keyType + ", " + valueType + ">";
                }
            }
        }
        return null;
    }

    private static final Map<String, String> TYPE_MAPPING = new HashMap<>();

    static {
        // 原始类型映射
        TYPE_MAPPING.put("int", "int");
        TYPE_MAPPING.put("long", "long");
        TYPE_MAPPING.put("double", "double");
        TYPE_MAPPING.put("boolean", "bool");
        TYPE_MAPPING.put("float", "float");
        TYPE_MAPPING.put("char", "char");
        TYPE_MAPPING.put("byte", "byte");
        TYPE_MAPPING.put("short", "short");

        // 包装类映射
        TYPE_MAPPING.put("java.lang.Integer", "int?");
        TYPE_MAPPING.put("java.lang.Long", "long?");
        TYPE_MAPPING.put("java.lang.Double", "double?");
        TYPE_MAPPING.put("java.lang.Boolean", "bool?");
        TYPE_MAPPING.put("java.lang.Float", "float?");
        TYPE_MAPPING.put("java.lang.Character", "char?");
        TYPE_MAPPING.put("java.lang.Byte", "byte?");
        TYPE_MAPPING.put("java.lang.Short", "short?");

        // 字符串特殊处理
        TYPE_MAPPING.put("java.lang.String", "string");

        // 集合类型映射
        TYPE_MAPPING.put("java.util.List", "List");
        TYPE_MAPPING.put("java.util.Set", "List");
        TYPE_MAPPING.put("java.util.Map", "Dictionary");

        // 日期类型
        TYPE_MAPPING.put("java.time.LocalDate", "DateTime");
        TYPE_MAPPING.put("java.time.LocalDateTime", "DateTime");

    }

    public static List<ProtoBufInfo> convertClassesToProtoBufInfos(Set<Class> classes) {
        List<ProtoBufInfo> result = new ArrayList<>();
        for (Class<?> clazz : classes) {
            ProtoBufInfo protoBufInfo = new ProtoBufInfo();
            protoBufInfo.setClassName(clazz.getSimpleName());
            if (clazz.getSuperclass() != null && clazz.getSuperclass() != Object.class) {
                protoBufInfo.setSuperClassName(clazz.getSuperclass().getSimpleName());
                protoBufInfo.setSuperClassFieldLength(clazz.getSuperclass().getDeclaredFields().length);
            }

            List<ParameterInfo> parameters = new ArrayList<>();
            for (Field field : clazz.getDeclaredFields()) {
                if (shouldSkipField(field)) continue;

                ParameterInfo param = new ParameterInfo();
                param.setName(field.getName());
                param.setType(getTypeName(field.getGenericType()));
                parameters.add(param);
            }

            protoBufInfo.setParameters(parameters);
            result.add(protoBufInfo);
        }
        return result;
    }

    private static boolean shouldSkipField(Field field) {
        int modifiers = field.getModifiers();
        return Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers);
    }

    private static String getTypeName(Type type) {
        if (type instanceof Class) {
            Class<?> clazz = (Class<?>) type;
            return resolveTypeName(clazz);
        } else if (type instanceof ParameterizedType) {
            return handleParameterizedType((ParameterizedType) type);
        } else if (type instanceof GenericArrayType) {
            return handleArrayType((GenericArrayType) type);
        } else if (type instanceof TypeVariable) {
            return handleTypeVariable((TypeVariable<?>) type);
        } else {
            return type.getTypeName(); // 其他类型直接返回原始名称
        }
    }

    private static String resolveTypeName(Class<?> clazz) {
        // 处理原始类型
        if (clazz.isPrimitive()) {
            return TYPE_MAPPING.get(clazz.getName());
        }

        // 处理已知映射类型
        String mappedName = TYPE_MAPPING.get(clazz.getName());
        if (mappedName != null) {
            return mappedName;
        }

        // 自定义对象返回简单类名
        return clazz.getSimpleName();
    }

    private static String handleParameterizedType(ParameterizedType pType) {
        StringBuilder sb = new StringBuilder();

        // 处理原始类型
        Type rawType = pType.getRawType();
        String rawTypeName = getTypeName(rawType);
        sb.append(rawTypeName);

        // 处理泛型参数
        Type[] typeArgs = pType.getActualTypeArguments();
        if (typeArgs.length > 0) {
            sb.append("<");
            for (int i = 0; i < typeArgs.length; i++) {
                if (i > 0) sb.append(", ");
                sb.append(getTypeName(typeArgs[i]));
            }
            sb.append(">");
        }
        return sb.toString();
    }

    private static String handleArrayType(GenericArrayType arrayType) {
        String componentType = getTypeName(arrayType.getGenericComponentType());
        return componentType + "[]";
    }

    private static String handleTypeVariable(TypeVariable<?> typeVariable) {
        // 处理泛型类型变量（如 T）
        return typeVariable.getName();
    }

}
